package cloud.pangui.core.mongo.element;

import com.mongodb.MongoException;
import org.bson.Document;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * 返回一个fun操作
 *
 * @Auther hepangui
 * @Date 2020/10/06 0001
*/
public class Func extends Ele {
	/**
	 * 加法
	 */
	public static final String ADD = "$add";
	/**
	 * 减法
	 */
	public static final String SUB = "$subtract";
	/**
	 * 乘法
	 */
	public static final String MUL = "$multiply";
	/**
	 * 除法
	 */
	public static final String DIV = "$divide";
	/**
	 * 取余
	 */
	public static final String MOD = "$mod";
	/**
	 * 拼接字符串
	 */
	public static final String CONCAT = "$concat";
	/**
	 * 截取字符串
	 */
	public static final String SUBSTR = "$substrCP";
	/**
	 * 字符串长度
	 */
	public static final String STRLEN = "$strLenCP";
	/**
	 * 转小写
	 */
	public static final String TOLOWER = "$toLower";
	/**
	 * 转大写
	 */
	public static final String TOUPPER = "$toUpper";
	/**
	 * null值转换
	 */
	public static final String IFNULL = "$ifNull";
	/**
	 * ifelse操作
	 */
	public static final String IFELSE = "$cond";

	/**
	 * 查数量
	 */
	public static final String COUNT = "$count";

	/**
	 * 从一个函数名获取一个函数
	 *
	 * @param funcName
	 * @param eles
	 * @return
	 */
	public static Ele ofName(String funcName, Ele[] eles) {
		switch (funcName) {
			case "add":
			case ADD:
				return add(eles);
			case "sub":
			case SUB:
				return sub(eles[0], eles[1]);
			case "mul":
			case MUL:
				return mul(eles[0], eles[1]);
			case "div":
			case DIV:
				return div(eles[0], eles[1]);
			case "concat":
			case CONCAT:
				return concat(eles);
			case "substr":
			case SUBSTR:
				if (eles.length != 3) {
					throw new MongoException("substr参数应为3个");
				}
				return substr(eles[0], eles[1], eles[2]);
			case "strlen":
			case STRLEN:
				return strlen(eles[0]);
			case "toLower":
			case TOLOWER:
				return toLower(eles[0]);
			case "toUpper":
			case TOUPPER:
				return toUpper(eles[0]);
			case "ifNull":
			case IFNULL:
				return ifNull(eles[0], eles[1]);
			case "ifElse":
			case IFELSE:
				if (eles.length != 3) {
					throw new MongoException("ifelse操作应为3个参数");
				}
				if (!(eles[0] instanceof Cond)) {
					throw new MongoException("ifelse操作第一个参数应为条件");
				}
				return ifElse((Cond) eles[0], eles[1], eles[2]);
		}
		List list = new ArrayList<>(eles.length);
		for (Ele ele : eles) {
			list.add(ele.toExpression());
		}
		Func func = new Func();
		func.doc = new Document(funcName, list);
		return func;
	}

	/**
	 * 设置doc
	 *
	 * @param doc
	 * @return
	 */
	public Func doc(Document doc) {
		this.doc = doc;
		return this;
	}

	@Override
	public Document build() {
		if (alias == null || "".equals(alias)) {
			throw new MongoException("函数对象应有别名");
		}
		if (doc == null) {
			throw new MongoException("函数元素结构不完整:");
		}
		return new Document(alias, doc);
	}

	/**
	 * 加法计算，将参数中的属性值相加
	 *
	 * @param eles
	 * @return
	 */
	public static Func add(Ele... eles) {
		List list = new ArrayList<>(eles.length);
		for (Ele ele : eles) {
			list.add(ele.toExpression());
		}
		return new Func().doc(new Document(ADD, list));
	}

	/**
	 * 加法计算，将一列加上某个值
	 *
	 * @param key
	 * @param value
	 * @return
	 */
	public static Func add(String key, Number value) {
		Ele[] eles = new Ele[2];
		eles[0] = Field.of(key);
		eles[1] = Value.of(value);
		return add(eles);
	}

	/**
	 * 将制定列相加
	 *
	 * @param keys
	 * @return
	 */
	public static Func add(String... keys) {
		Ele[] eles = new Ele[keys.length];
		for (int i = 0; i < keys.length; i++) {
			eles[i] = Field.of(keys[i]);
		}
		return add(eles);
	}

	/**
	 * 减法运算
	 *
	 * @param key   元素
	 * @param value 减去的值
	 * @return
	 */
	public static Func sub(String key, Number value) {
		return sub(Field.of(key), Value.of(value));
	}

	/**
	 * 减法运算
	 *
	 * @param e1 元素1
	 * @param e2 元素2
	 * @return
	 */
	public static Func sub(Ele e1, Ele e2) {
		List list = new ArrayList<>(2);
		list.add(e1.toExpression());
		list.add(e2.toExpression());
		return new Func().doc(new Document(SUB, list));
	}


	/**
	 * 乘法运算
	 *
	 * @param key   元素
	 * @param value 值
	 * @return
	 */
	public static Func mul(String key, Number value) {
		return mul(Field.of(key), Value.of(value));
	}

	/**
	 * 乘法运算
	 *
	 * @param e1 元素1
	 * @param e2 元素2
	 * @return
	 */
	public static Func mul(Ele e1, Ele e2) {
		List list = new ArrayList<>(2);
		list.add(e1.toExpression());
		list.add(e2.toExpression());
		return new Func().doc(new Document(MUL, list));
	}

	/**
	 * 除法运算
	 *
	 * @param key   元素
	 * @param value 值
	 * @return
	 */
	public static Func div(String key, Number value) {
		return div(Field.of(key), Value.of(value));
	}

	/**
	 * 除法运算
	 *
	 * @param e1 元素1
	 * @param e2 元素2
	 * @return
	 */
	public static Func div(Ele e1, Ele e2) {
		List list = new ArrayList<>(2);
		list.add(e1.toExpression());
		list.add(e2.toExpression());
		return new Func().doc(new Document(DIV, list));
	}

	/**
	 * 取余
	 *
	 * @param key   元素
	 * @param value 减去的值
	 * @return
	 */
	public static Func mod(String key, Number value) {
		return mod(Field.of(key), Value.of(value));
	}

	/**
	 * 取余
	 *
	 * @param e1 元素1
	 * @param e2 元素2
	 * @return
	 */
	public static Func mod(Ele e1, Ele e2) {
		List list = new ArrayList<>(2);
		list.add(e1.toExpression());
		list.add(e2.toExpression());
		return new Func().doc(new Document(MOD, list));
	}

	/**
	 * 拼接指定的列值
	 *
	 * @param keys
	 * @return
	 */
	public static Func concat(String... keys) {
		Ele[] eles = new Ele[keys.length];
		for (int i = 0; i < keys.length; i++) {
			eles[i] = Field.of(keys[i]);
		}
		return concat(eles);
	}

	/**
	 * 拼接元素
	 *
	 * @param eles
	 * @return
	 */
	public static Func concat(Ele... eles) {
		List list = new ArrayList<>(eles.length);
		for (Ele ele : eles) {
			list.add(ele.toExpression());
		}
		return new Func().doc(new Document(CONCAT, list));
	}

	/**
	 * 截取字符串
	 *
	 * @param ele    表达式
	 * @param start  开始
	 * @param length 结束
	 * @return
	 */
	public static Func substr(Ele ele, Ele start, Ele length) {
		List list = new ArrayList<>(3);
		list.add(ele.toExpression());
		list.add(start.toExpression());
		list.add(length.toExpression());
		return new Func().doc(new Document(SUBSTR, list));
	}

	/**
	 * 截取字符串
	 *
	 * @param key    列名
	 * @param start  开始
	 * @param length 截取的长度
	 * @return
	 */
	public static Func substr(String key, int start, int length) {
		return substr(Field.of(key), Value.of(start), Value.of(length));
	}

	/**
	 * 截取字符串，截取到最后
	 *
	 * @param key   列名
	 * @param start 开始
	 * @return
	 */
	public static Func substr(String key, int start) {
		// length 保证大于要截取的长度，直接使用length作为长度，肯定是截取到最后了
		return substr(Field.of(key), Value.of(start), Func.strlen(key));
	}

	/**
	 * 获取字符串长度的函数
	 *
	 * @param key
	 * @return
	 */
	public static Func strlen(String key) {
		return strlen(Field.of(key));
	}

	/**
	 * 获取字符串长度的函数
	 *
	 * @param ele
	 * @return
	 */
	public static Func strlen(Ele ele) {
		return new Func().doc(new Document(STRLEN, ele.toExpression()));
	}

	/**
	 * 转小写
	 *
	 * @param key
	 * @return
	 */
	public static Func toLower(String key) {
		return toLower(Field.of(key));
	}

	/**
	 * 转小写
	 *
	 * @param key
	 * @return
	 */
	public static Func toLower(Ele key) {
		return new Func().doc(new Document(TOLOWER, key.toExpression()));
	}

	/**
	 * 转大写
	 *
	 * @param key
	 * @return
	 */
	public static Func toUpper(String key) {
		return toUpper(Field.of(key));
	}

	/**
	 * 转大写
	 *
	 * @param key
	 * @return
	 */
	public static Func toUpper(Ele key) {
		return new Func().doc(new Document(TOUPPER, key.toExpression()));
	}

	/**
	 * 返回一个ifelse的判断
	 *
	 * @param ifEle   判断条件
	 * @param thenEle 当判断条件为true时
	 * @param elseEle 当判断条件为false时
	 * @return
	 */
	public static Func ifElse(Cond ifEle, Ele thenEle, Ele elseEle) {
		return new Func().doc(new Document(IFELSE,
				Arrays.asList(new Object[]{ifEle.toExpression(), thenEle.toExpression(), elseEle.toExpression()})));
	}

	/**
	 * 截取字符串
	 *
	 * @param key    列名
	 * @param result 结束
	 * @return
	 */
	public static Func ifNull(Ele key, Ele result) {
		List list = new ArrayList<>(2);
		list.add(key.toExpression());
		list.add(result.toExpression());
		return new Func().doc(new Document(IFNULL, list));
	}

}
